home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / pcxpas.com / PCX.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1990-10-15  |  8.6 KB  |  229 lines

  1. unit PCX;
  2.  
  3. (* This is a unit to read .PCX files and put them in displayable form. The
  4.    actual work of decoding the file and moving the data into memory is done
  5.    in assembler and is quite fast. (You don't need TASM or any knowledge of
  6.    assembly language. As long as PCXOBJ.OBJ is present, it will be linked
  7.    into the unit when you compile.)
  8.  
  9.    The following display modes are supported:
  10.  
  11.           Mode      TP Graphmode     Resolution    Colors
  12.           ~~~~      ~~~~~~~~~~~~     ~~~~~~~~~~    ~~~~~~
  13.           $04       CGAC0 to C3      320 x 200        4
  14.           $06       CGAHi            640 x 200        2
  15.           $0E       EGALo/VGALo      640 x 200       16
  16.           $10       EGAHi/VGAMed     640 x 350       16
  17.           $12       VGAHi            640 x 480       16
  18.  
  19.    Some tinkering would no doubt make the unit usable with the 320 x
  20.    200 x 16-color modes. The 320 x 200 x 256-color mode is dealt with in a
  21.    companion unit, PCX256.PAS.
  22.  
  23.    It's assumed that the image is the width of the screen and that you will
  24.    set the correct display mode. The unit doesn't check to see what format
  25.    the .PCX image is in, and you have to pass in the appropriate driver
  26.    as a parameter.
  27.  
  28.    For the CGA formats, the unit is set up to put the data into two buffers
  29.    on the heap, from where it can be moved into the two display memory
  30.    banks. See CGASHOW for an example. You can of course alter the unit
  31.    to move the data directly into display memory.
  32.  
  33.    For EGA and VGA formats, the data is written to page 0 of the video
  34.    buffer. This can easily be changed by setting "page_addr" to a different
  35.    value. Three different techniques of hiding the image while it is being
  36.    written are demonstrated in SHOWEGA, SHOWVGA, and SHOW256.
  37.  
  38.    References:
  39.    ~~~~~~~~~~
  40.    Richard F. Ferraro, "Programmer's Guide to the EGA and VGA Cards"
  41.    (Addison-Wesley, 1988).
  42.  
  43.    Richard Wilton, "Programmer's Guide to PC and PS/2 Video Systems"
  44.    (Microsoft, 1987).
  45.  
  46.    "Technical Reference Manual [for Paintbrush]" (Zsoft, 1988). The
  47.    information in this slim booklet is also found in a file distributed
  48.    with at least some versions of Microsoft/PC Paintbrush.
  49.  
  50.    Software:
  51.    ~~~~~~~~
  52.    Besides the various incarnations of Paintbrush (ZSoft and Microsoft),
  53.    the excellent Deluxe Paint II Enhanced (Electronic Arts) can also create
  54.    files in .PCX format. Other graphics programs have conversion utilities.
  55.    *)
  56.  
  57. (* --------------------------------------------------------------------- *)
  58.  
  59. INTERFACE
  60.  
  61. uses DOS, GRAPH;
  62.  
  63. type    RGBrec = record
  64.                    redval, greenval, blueval: integer;
  65.                  end;
  66.  
  67. var     pcxfilename: pathstr;
  68.         file_error: boolean;
  69.         pal: palettetype;
  70.         RGBpal: array[0..15] of RGBrec;
  71.         page_addr: word;
  72.         buff1, buff2: pointer;
  73.  
  74.         { CGA display memory banks: }
  75.         screenbuff1: array[0..7999] of byte absolute $b800:$0000;
  76.         screenbuff2: array[0..7999] of byte absolute $b800:$2000;
  77.  
  78. const   page0 = $A000;                        { EGA/VGA display segment }
  79.         EGApage1 = $A800;
  80.  
  81. procedure READ_PCX_FILE(pdriver: integer; pfilename: pathstr);
  82.  
  83. (* ------------------------------------------------------------------ *)
  84.  
  85. IMPLEMENTATION
  86.  
  87. var     datalength: word;
  88.         scratch: pointer;
  89.         buff1seg, buff2seg: word;
  90.         plane: word;
  91.         is_CGA: boolean;
  92.         is_VGA: boolean;
  93.         evenrow: boolean;
  94.         repeatcount: byte;
  95.         columncount, linestart: word;
  96.  
  97. type    ptrRec = record
  98.                    ofs, seg: word;
  99.                  end;
  100.  
  101. const   buffsize = 65521;              { Largest possible }
  102.  
  103. procedure DECODE_PCX; external;
  104. {$L pcxobj}
  105.  
  106. procedure READ_PCX_FILE(pdriver: integer; pfilename: pathstr);
  107.  
  108. var     entry, gun, pcxcode, mask, colorID: byte;
  109.         palbuf: array[0..47] of byte;
  110.         pcxfile: file;
  111.  
  112. begin   { READ_PCX_FILE }
  113. is_CGA:= (pdriver = CGA);                              { 2 or 4 colors }
  114. is_VGA:= (pdriver = VGA);                 { 16 of 256K possible colors }
  115.                             { Otherwise EGA - 16 of 64 possible colors }
  116. assign(pcxfile, pfilename);
  117. {$I-} reset(pcxfile, 1);  {$I+}
  118. file_error:= (IOresult <> 0);
  119. if file_error then exit;
  120.  
  121. (* To minimize disk access and speed things up, we read the file into a
  122.    scratchpad on the heap. Large files have to be done in two or more
  123.    chunks because of the 64K limit on dynamic memory variables. *)
  124.  
  125. getmem(scratch, buffsize);                 { Allocate scratchpad }
  126. blockread(pcxfile, scratch^, 128);         { Get header into scratchpad }
  127.  
  128. (* The .PCX file has a 128-byte header. Most of it can be ignored if you're
  129.    working with a known format. All we want is the palette information. *)
  130.  
  131. inc(ptrRec(scratch).ofs, 16);              { Scrap first 16 bytes }
  132. move(scratch^, palbuf, 48);                { Get palette info }
  133.  
  134. (* ------------------------ Setup for CGA ----------------------------- *)
  135.  
  136. if is_CGA then
  137. begin                                      { Allocate memory for CGA map }
  138.   getmem(buff1, 8000);
  139.   getmem(buff2, 8000);
  140.   buff1seg:= ptrRec(buff1).seg;      { Segment of buffers, for assembler }
  141.   buff2seg:= ptrRec(buff2).seg;
  142.   evenrow:= false;
  143. end else
  144.  
  145. (* ---------------------- Setup for EGA/VGA ---------------------------- *)
  146.  
  147. begin
  148.   port[$3C4]:= 2;                          { Index to map mask register }
  149.   plane:= 1;                               { Initialize plane }
  150.   port[$3C5]:= plane;          { Set sequencer to mask out other planes }
  151.  
  152. (* -------------------- Decipher EGA/VGA palette ----------------------- *)
  153.  
  154. (* The palette information is stored in bytes 16-63 of the header. Each of
  155.    the 16 palette slots is allotted 3 bytes - one for each primary color.
  156.    Any of these bytes can have a value of 0-255.
  157.  
  158.    For the EGA there are just 4 significant settings, since only 64
  159.    different colors (4 x 4 x 4) are available. Hence for EGA-format images
  160.    we divide the codes by 64. The absolute color number for the palette
  161.    entry is derived by setting one of bits 0-2 and one of bits 3-5 with the
  162.    mask corresponding to the .PCX code byte. (In binary form, the absolute
  163.    color number may be thought of as 00rgbRGB.) This number is then passed
  164.    into Turbo's SetAllPalette procedure.
  165.  
  166.    For the VGA things work differently. Here we must use Turbo's
  167.    SetRGBPalette procedure to change the red, green, and blue values in the
  168.    16 active color registers. The registers expect values in the range 0-63
  169.    (64 x 64 x 64 = 256K, the number of possible colors), so we divide the
  170.    .PCX codes by 4. A further complication is that by default the palette
  171.    entries point to the color registers corresponding to the standard EGA
  172.    colors, so we must change them to point to registers 0-15 instead (or
  173.    else modify registers 0-5, 20, 7, and 56-63). See SHOWVGA.PAS for an
  174.    example of how to set the palette and the registers. *)
  175.  
  176.   for entry:= 0 to 15 do
  177.   begin
  178.     colorID:= 0;
  179.     for gun:= 0 to 2 do
  180.     begin
  181.       pcxcode:= palbuf[entry * 3 + gun];     { Get primary color value }
  182.       if not is_VGA then
  183.       begin                                  { Interpret for EGA }
  184.         case (pcxcode div $40) of
  185.           0: mask:= $00;    { 000000 }
  186.           1: mask:= $20;    { 100000 }
  187.           2: mask:= $04;    { 000100 }
  188.           3: mask:= $24;    { 100100 }
  189.         end;
  190.         colorID:= colorID or (mask shr gun);   { Define two bits }
  191.       end  { not is_VGA }
  192.       else
  193.       begin  { is_VGA }
  194.         with RGBpal[entry] do                { Interpret for VGA }
  195.         case gun of
  196.           0: redval:= pcxcode div 4;
  197.           1: greenval:= pcxcode div 4;
  198.           2: blueval:= pcxcode div 4;
  199.         end;
  200.       end;  { is_VGA }
  201.     end;  { gun }
  202.     if is_VGA then pal.colors[entry]:= entry
  203.               else pal.colors[entry]:= colorID;
  204.   end;  { entry }
  205.   pal.size:= 16;
  206. end;   { not is_CGA }
  207.  
  208. (* ----------------- Read and decode the image data ------------------- *)
  209.  
  210. dec(ptrRec(scratch).ofs, 16);           { Reset pointer }
  211. repeatcount:= 0;                        { Initialize assembler vars. }
  212. columncount:= 0;
  213. linestart:= 0;
  214. repeat
  215.   blockread(pcxfile, scratch^, buffsize, datalength);
  216.   decode_pcx;                           { Call assembler routine }
  217. until eof(pcxfile);
  218. close(pcxfile);
  219. if not is_CGA then port[$3C5]:= $F;     { Reset mask map }
  220. freemem(scratch,buffsize);              { Discard scratchpad }
  221. end;  { READ_PCX_FILE }
  222.  
  223. (* -------------------------- Initialization ----------------------------- *)
  224.  
  225. BEGIN
  226. page_addr:= page0;                      { Destination for EGA/VGA data }
  227. END.
  228.  
  229.